﻿#include "protocolstream.h"
#include <assert.h>
#include <cstring>
#include <qendian.h>    //QtEndian void qToBigEndian(T src, uchar * dest)

using namespace std;

namespace yt
{
	unsigned short checksum(const unsigned short *buffer, int size)
	{
		unsigned int cksum = 0;
		while (size > 1)
		{
			cksum += *buffer++;
			size -= sizeof(unsigned short);
		}
		//size为奇数的情况
		if (size)
		{
			cksum += *(unsigned char*)buffer;
		}
		//将32位转换成16位,用while是因为有可能进位
		while (cksum >> 16)
			cksum = (cksum >> 16) + (cksum & 0xffff);
		return (unsigned short)(~cksum);
	}

	////数字压缩算法zigzag，将无符号数i压缩，去掉前面的0，最多32位用5个字节保存，
	////但是大多数情况下都是不大的数，2-3字节就能保存，转换后的内容保存到buf中，字节数保存在len中
	bool compress_(unsigned int i, char *buf, size_t &len)
	{
		len = 0;
		for (int a = 4; a >= 0; a--)
		{
			char c;
			c = i >> (a * 7) & 0x7f;
			if (c == 0x00 && len == 0)
				continue;
			//除去最后一个字节，其他字节最高位都用1标记
			if (a == 0)
				c &= 0x7f;
			else
				c |= 0x80;
			buf[len] = c;
			len++;
		}
		if (len == 0)
		{
			len++;
			buf[0] = 0;
		}

		//cout << "compress:" << i << endl;
		//cout << "compress len:" << len << endl;
		return true;
	}

	bool uncompress_(char *buf, size_t len, unsigned int &i)
	{
		i = 0;
		for (int index = 0; index < (int)len; index++)
		{
			char c = *(buf + index);
			i = i << 7;

			c &= 0x7f;
			i |= c;
		}
		//cout << "uncompress:" << i << endl;
		return true;
	}

	BinaryReadStream2::BinaryReadStream2(const char* ptr_, size_t len_)
		:ptr(ptr_), len(len_), cur(ptr_)
	{
		//这里为何跳过这几个字节？
		cur += BINARY_PACKLEN_LEN_2 + CHECKSUM_LEN;
	}

	const char* BinaryReadStream2::GetData() const
	{
		return ptr;
	}
	size_t BinaryReadStream2::GetSize() const
	{
		return len;
	}
	bool BinaryReadStream2::IsEmpty() const
	{
		return len <= BINARY_PACKLEN_LEN_2;
	}
	//拷贝一个数据包的数据(cur指针指向的数据)到str开始的内存
	bool BinaryReadStream2::Read(char* str, size_t strlen, /* out */ size_t& outlen)
	{
		size_t fieldlen;
		size_t headlen;
		if (!ReadLengthWithoutOffset(headlen, fieldlen)) return false;

		// user buffer is not enough
		if (fieldlen > strlen) {
			return false;
		}
		//偏移到数据位置
		//cur += BINARY_PACKLEN_LEN_2;	
		cur += headlen;
		if (cur + fieldlen > ptr + len)
		{
			outlen = 0;
			return false;
		}
		memcpy(str, cur, fieldlen);
		outlen = fieldlen;
		//ptr或者len不需要增加？
		cur += outlen;
		return true;
	}
	//headlen数据头的长度，outlen是数据头表示的长度
	bool BinaryReadStream2::ReadLengthWithoutOffset(size_t &headlen, size_t & outlen)
	{
		headlen = 0;
		const char *temp = cur;
		char buf[5];
		for (size_t i = 0; i < sizeof(buf); i++)
		{
			memcpy(buf + i, temp, sizeof(char));
			temp++;
			headlen++;
			//取出压缩后的数字
			if ((buf[i] & 0x80) == 0x00) break;
		}

		if (cur + headlen > ptr + len) return false;
		unsigned int value;
		uncompress_(buf, headlen, value);
		outlen = value;

		/*if ( cur + BINARY_PACKLEN_LEN_2 > ptr + len ) {
		return false;
		}

		unsigned int tmp;
		memcpy(&tmp, cur, sizeof(tmp));
		outlen = ntohl(tmp);*/
		return true;
	}
	//将str的数据替换成一个数据包
	bool BinaryReadStream2::Read(string *str, size_t maxlen, size_t& outlen)
	{
		size_t headlen;
		size_t fieldlen;
		if (!ReadLengthWithoutOffset(headlen, fieldlen)) {
			return false;
		}

		// user buffer is not enough
		if (maxlen != 0 && fieldlen > maxlen) {
			return false;
		}

		// 偏移到数据的位置
		//cur += BINARY_PACKLEN_LEN_2;	
		cur += headlen;
		if (cur + fieldlen > ptr + len)
		{
			outlen = 0;
			return false;
		}
		//字符串替换
		str->assign(cur, fieldlen);
		outlen = fieldlen;
		cur += outlen;
		return true;
	}

	bool BinaryReadStream2::Read(const char** str, size_t maxlen, size_t& outlen)
	{
		size_t headlen;
		size_t fieldlen;
		if (!ReadLengthWithoutOffset(headlen, fieldlen)) {
			return false;
		}
		// user buffer is not enough
		if (maxlen != 0 && fieldlen > maxlen) {
			return false;
		}

		// 偏移到数据的位置
		//cur += BINARY_PACKLEN_LEN_2;	
		cur += headlen;

		//memcpy(str, cur, fieldlen);
		if (cur + fieldlen > ptr + len)
		{
			outlen = 0;
			return false;
		}
		*str = cur;
		outlen = fieldlen;
		cur += outlen;
		return true;
	}
	//读取一个int的数据？需要从网络字节序转为本地字节序？
	bool BinaryReadStream2::Read(int &i)
	{
		const int VALUE_SIZE = sizeof(int);

		if (cur + VALUE_SIZE > ptr + len) {
			return false;
		}

		memcpy(&i, cur, VALUE_SIZE);
		
        i = qFromBigEndian<int>(i);
        //i = ntohl(i);

		cur += VALUE_SIZE;

		return true;
	}
	//读取一个short数据？ntohs?
	bool BinaryReadStream2::Read(short &i)
	{
		const int VALUE_SIZE = sizeof(short);

		if (cur + VALUE_SIZE > ptr + len) {
			return false;
		}

		memcpy(&i, cur, VALUE_SIZE);
        //i = ntohs(i);
        i = qFromBigEndian<short>(i);

		cur += VALUE_SIZE;

		return true;
	}
	//读取一个char数据？
	bool BinaryReadStream2::Read(char &c)
	{
		const int VALUE_SIZE = sizeof(char);

		if (cur + VALUE_SIZE > ptr + len) {
			return false;
		}

		memcpy(&c, cur, VALUE_SIZE);
		cur += VALUE_SIZE;

		return true;
	}
	//直接丢弃了一个数据包？
	bool BinaryReadStream2::ReadLength(size_t & outlen)
	{
		size_t headlen;
		if (!ReadLengthWithoutOffset(headlen, outlen)) {
			return false;
		}

		//cur += BINARY_PACKLEN_LEN_2;
		cur += headlen;
		return true;
	}
	bool BinaryReadStream2::IsEnd() const
	{
		assert(cur <= ptr + len);
		return cur == ptr + len;
	}
	//读取所有数据
	size_t BinaryReadStream2::ReadAll(char * szBuffer, size_t iLen) const
	{
		size_t iRealLen = min(iLen, len);
		memcpy(szBuffer, ptr, iRealLen);
		return iRealLen;
	}
    /**
     * @brief BinaryWriteStream3::BinaryWriteStream3    类初始化
     * @param data
     */
	BinaryWriteStream3::BinaryWriteStream3(string *data) : 
		m_data(data)
	{
		m_data->clear();
		char str[BINARY_PACKLEN_LEN_2 + CHECKSUM_LEN];
        //占位符,这里必须要先这样占位，然后后续读算出整体长度后在插入
        m_data->append(str, sizeof(str));
	}

	const char* BinaryWriteStream3::GetData() const
	{
		return m_data->data();
	}

	size_t BinaryWriteStream3::GetSize() const
	{
		return m_data->length();
	}
	//插入str指针指向的地址开始的len字节数据
	//+-------------+-------------+-------------+----------+----------+------+
	//|   PACKLEN   |CHECKSUM_LEN | buf(headlen)| cmd(int) | seq(int) | data |
	//+-------------+-------------+-------------+----------+----------+------+
	bool BinaryWriteStream3::Write(const char* str, size_t len)
	{
		char buf[5];
		size_t buflen;
		compress_(len, buf, buflen);
		m_data->append(buf, sizeof(char)*buflen);

		m_data->append(str, len);

		//unsigned int ulen = htonl(len);
		//m_data->append((char*)&ulen,sizeof(ulen));
		//m_data->append(str,len);
		return true;
	}
    /**
     * @brief BinaryWriteStream3::Write 从cur地址处追加一个int
     * @param i
     * @param isNULL    false(默认转为大端字节序)
     * @return
     */
	bool BinaryWriteStream3::Write(int i, bool isNULL)
	{
		int i2 = 999999999;
		if (isNULL == false)
        {
            //i2 = htonl(i);
            i2 = qToBigEndian<int>(i);
        }

		m_data->append((char*)&i2, sizeof(i2));
		return true;
	}
    /**
     * @brief BinaryWriteStream3::Write 从cur地址处追加一个short
     * @param i
     * @param isNULL
     * @return
     */
	bool BinaryWriteStream3::Write(short i, bool isNULL)
	{
		short i2 = 0;
		if (isNULL == false)
        {
            //i2 = htons(i);
            i2 = qToBigEndian<short>(i);
        }

		m_data->append((char*)&i2, sizeof(i2));
		return true;
	}
    /**
     * @brief BinaryWriteStream3::Write 从cur地址处追加一个short
     * @param c
     * @param isNULL
     * @return
     */
	bool BinaryWriteStream3::Write(char c, bool isNULL)
	{
		char c2 = 0;
		if (isNULL == false)
			c2 = c;
		(*m_data) += c2;
		return true;
	}

	bool BinaryWriteStream3::Write(double value, bool isNULL)
	{
		char   doublestr[128];
		if (isNULL == false)
		{
			sprintf(doublestr, "%f", value);
			Write(doublestr, strlen(doublestr));
		}
		else
			Write(doublestr, 0);
		return true;
	}

	bool BinaryWriteStream3::Write(long value, bool isNULL)
	{
		char int64str[128];
		if (isNULL == false)
		{
			sprintf(int64str, "%ld", value);
			Write(int64str, strlen(int64str));
		}
		else
			Write(int64str, 0);
		return true;
	}

    /**
     * @brief BinaryWriteStream3::Flush
     * PACKLEN四字节处插入整个m_data的长度
     */
	void BinaryWriteStream3::Flush()
	{
		char *ptr = &(*m_data)[0];
        unsigned int ulen = qToBigEndian<unsigned int>(m_data->length());
        //unsigned int ulen = htonl(m_data->length());
		memcpy(ptr, &ulen, sizeof(ulen));
	}

    /**
     * @brief BinaryWriteStream3::Clear     格式化，清空m_data内容，并且重新加上固定头
     */
	void BinaryWriteStream3::Clear()
	{
		m_data->clear();
		char str[BINARY_PACKLEN_LEN_2 + CHECKSUM_LEN];
		m_data->append(str, sizeof(str));
	}
}
